D3JsDay16 It's map birth,It's from path—生出地圖
2021-10-01 Fri
昨天介紹完關於Web地圖的相關知識之後今天我們要開始使用geojson的資料來繪製一個地圖首先我們到以下的網站下載shp檔案
轉換格式工具
工具一 mapshaper
由於要繪製地圖的時候我們必須使用geojson的格式進行,在網路上得到的資源是屬於shapefile的格式,所以要先進行轉換成geojson
D3jeo官方API文件提到如下圖

D3的作者也進行了開源專案讓shp轉換成geojson可以參考以下連結
我們使用另一個方式線上進行轉換
首先進到mapshaper網站之後將從政府開放平台資料下載的檔案解壓縮之後的shp拖曳到畫面當中,按下import

基本上會看到預覽圖如下

另外可以點擊右上角的simplify做壓縮

看到這個畫面之後按Apply

這時候畫面上方會多一個可以拉動0到100%的設定如下圖

你可以嘗試著拉動它這邊拉動至0%試試看如下圖,你就知道為什麼台灣會被說像番薯了

這裡我們調整大概80%左右如下圖

按下右上角的Export應該會看到如下圖

這裡我們選擇topoJson按下export之後應該就會開始下載了,做到這一步基本上你會得到一個json檔案
工具二 topojson
我們剛剛輸出的是topojson先前提到整體檔案會比geojson來的小,當我們後續要撰寫程式碼的時候也必須將topojson轉換成geojson這邊可以使用CDN的方式也就是載入連結的方式引入到腳本中或是npm安裝,我們使用CDN的方式
基本上打開下面的網頁滾動到下方把這行複製到你的網頁的head裡面就可以了。

感受程式碼
這一次換個解說方式,我們先行給予程式碼來讓各位感受一下,還不了解沒關係,等等將會講解重要函式的作用
const width = 800;
const height = 600;
const svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
const projection = d3.geoMercator();
console.log(typeof(projection));
const path = d3.geoPath()
.projection(projection);
const g = svg.append("g"); //先行撰寫一個g群組以便之後要插入path屬性
d3.json("World_Countries.json").then(function(topojsonData) {
console.log(topojsonData);
const convertedGeojson =topojson
.feature(topojsonData, topojsonData.objects.World_Countries);
const getGeoFeature = convertedGeojson.features;
g.selectAll("path")
.data(
getGeoFeature
)
.join("path")
.attr("d", path)
;
})Projection函式介紹
打開官方文件在安裝的那一欄就就有寫到要先宣告一個projection,然後使用geoPath路徑生成器來指定投影方式
這裡projection翻成中文是投影的意思
如下圖

因此我們撰寫程式碼了解一下projection是什麼東西如下
const projection = d3.geoMercator();
console.log(typeof(projection));這時候我們使用console.log(typeof(projection)),它會說是一個函式
如下圖

官方API文件說明是將球面的多邊形幾何轉換成平面的多邊形幾何,簡單說就是先前地理知識將球影投影到平面上的意思
官方說明如下圖

geopath函式介紹
我們先看官方API說明如下圖

- 需要知道的第一點是官方提到這裡是一個路徑產生器,可以指定投影方式,我們上一個部分介紹到的projection將會派上用場
- 需要知道的第二點是這一行說明Renders the given object, which may be any GeoJSON feature or geometry object:這邊意思是
path函式要進行轉換的時候需要帶入的是GeoJSON的feature先記得這個說明之後會用到
topojson轉換函式
這個時候到官方API文件滑到下方點擊這個有寫到轉換topojson到geojson
topojson.feature - convert TopoJSON to GeoJSON.
因此我們要用的是這個函式

官方有提到接受物件如果是GeometryCollection會將每個幾何圖形映射到Feature

這時候我們撰寫程式碼,一樣使用先前提到的json載入資料方式來載入世界地圖,然後觀看一下console.log的內容
d3.json("World_Countries.json").then(function(topojsonData) {
console.log(topojsonData);
})
如上圖打開console.log看objects的World_Countries那一欄顯示裡面的東西是GeometryCollection正是我們需要的東西。
所以我們宣告一個convertedGeojson來儲存剛剛的東西,目前為止是將topojson轉換成geojson存入變數convertedgeojson中
程式碼如下
d3.json("World_Countries.json")
.then(function(topojsonData) {
console.log(topojsonData);
const convertedGeojson =topojson
.feature(topojsonData, topojsonData.objects.World_Countries);
})組合程式碼
上面介紹完這三個函式的用途之後 我們回頭看剛剛所給各位感受的程式碼 具體步驟如下
- 宣告一個porjection變數來取得某個投影方法函式
- 將剛剛的投影方法指定至path路徑產生器
- 找尋topojson資料中的GeometryCollection物件來透過
topojson函式轉換 - 使用
path路徑函式將轉換後的geojson提取出features進行繪製
因此剛剛的程式碼
第6行就是宣告一個投影方式
第8行宣告一個路徑產生器來指定投影方式
第13行使用topojson的feature函式將GeometryCollection轉換至Geojson
第14行將Geojson的features提取出來當成之後要使用path函式的參數
最後的樣貌應該會如下圖
明天再來教學如何美化這個地圖和顯示地圖相關區域
